/*
 * StorageResource.cpp
 *
 *  Created on: 04/10/2009
 *      Author: nik0l4z
 */

#include "../../Model/StorageResource.h"


StorageResource::StorageResource() {
/*No deberia nunca contener nada este constructor. Ya que la responsabilidad de creacion de un recurso, y
 * el posterior seteo de sus estrategias, queda delegado totalmente en la factory.

 * Solo se perimite
 * setear el comportamiento del Compresor que es cross a todo el toolkit
 */
    /*Por default el compresor no se usa*/

	this->compressMode = false;

}

StorageResource::~StorageResource() {

	cout << "Se elimina recurso de almacenamiento " << endl;

	sleep (1);

	int resultado=0;

	while (resultado!=-2){

		this->resourceStrategy->persistOldData();

		if (resourceStrategy->getStorage()!=NULL){

			resultado = resourceStrategy->getStorage()->getOldData();
		}else resultado=-2;

	}

	delete this->indexStategy;
	delete this->resourceStrategy;
	delete this->storageStrategy;
    delete this->data;

}

	void StorageResource::setData(Dato *data){
		this->data = data;
		this->data->setPersisted(false);
	}

	void StorageResource::setData(list<Dato*> dataList){
		this->dataList = dataList;
	}
/*-----------------Metodos de ABM---------------------------------------------------------------------------*/

	/**
	 * Metodo que que se fija si tiene informacion para guardar, tirando una excepcion en caso contrario.
	 * Guarda la informacion alojada en dataList y/o la alojada en data
	 */
	void StorageResource::saveData() {
		if ( (this->data == NULL) && ( this->dataList.size() == 0) ){
		      throw std::ios_base::failure("[StorageResource::deleteData]  El recurso no contiene ningun dato para almacenar");
		}

		if ((this->data != NULL) && (!this->data->isPersisted())){
			this->saveSingleData(this->data,this->clave);
			this->data->setPersisted(true);
		}

		if (this->dataList.size() != 0){
			 for(iterator = dataList.begin(); iterator != dataList.end(); ++iterator){

				 Dato *dato =(Dato*) (*iterator);

			      if (!dato->isPersisted()){
			    	  Clave *clave;
			    	  clave= new Clave("",dato);
			    	  this->setClave(clave);
			    	  this->saveSingleData(dato,clave);
			    	  dato->setPersisted(true);
			    	  delete clave;
			      }
			      delete dato;
			 }
		}
	}

	void StorageResource::saveSingleData(Dato *data,Clave *clave){

		/* Debido a la arquitectura que envuelve a ambos indices bajo una misma interfaz, y su compartamiento
		  no es el mismo, se recurre a este WorkAround */
		if( this->getIndexStategy()->getClassName( )== Hash ) {
			this->saveSingleDataHash(data, clave);
			return;
		}

		this->saveSingleDataBSharp(data,clave);
	}


	void StorageResource::saveSingleDataHash(Dato *data,Clave *clave){

		int fileReference;

		bool isUnique = this->getIndexStategy()->checkUniqueness(this->getClave(),data);

		if (isUnique) this->getIndexStategy()->updateIndex(fileReference,clave,data);

		this->getResourceStrategy()->persistOldData();

	}

	void StorageResource::saveSingleDataBSharp(Dato *data,Clave *clave){

		bool isUnique = this->getIndexStategy()->checkUniqueness(this->getClave(),data);

		if (isUnique) {
			int fileReference = this->getStorageStrategy()->saveData(data);
			this->getIndexStategy()->updateIndex(fileReference,clave,data);

			this->getResourceStrategy()->persistOldData();


		}
		else{
			throw std::ios_base::failure("[StorageResource::saveSingleDataBSharp]  Error, se quizo insertar una clave duplicada");
		}
	}

	void StorageResource::deleteData(list<Clave*> claves){
		list<Clave*>::iterator iterator;

		for(iterator = claves.begin(); iterator != claves.end(); ++iterator){
			Clave *clave =(*iterator);
			this->deleteData(clave);
		}
	}

	void StorageResource::deleteData(Clave *clave){
		if (clave == NULL){
			throw std::ios_base::failure("[StorageResource::deleteData]  La clave es Nula");
		}

		if (this->getIndexStategy()->getClassName()==Hash) {

			this->deleteDataHash(clave);
			return;
		}

		this->deleteDataBSharp(clave);
	}

	void StorageResource::deleteDataHash(Clave *clave){

		this->getIndexStategy()->deleteKey(clave);

	}

	void StorageResource::deleteDataBSharp(Clave *clave){

		/*Devuelve la referencia a la estructura (archivo / buffer) en donde se encuentra la clave
		  pasada por parametro*/
		int fileReference = this->getIndexStategy()->getStorageReferenceByKey(clave);

		if (fileReference != -1){
			this->getStorageStrategy()->deleteData(fileReference);
			//Borra la clave del indice
			this->getIndexStategy()->deleteKey(clave);
		}

	}

	void StorageResource::updateData(Dato *data,Clave *clave) {
		if (data == NULL && clave == NULL) {
			throw std::ios_base::failure("[StorageResource::updateData] Datos obligatorios nulos");
		}

		if (this->getIndexStategy()->getClassName()==Hash) {
			this->updateDataHash(data,clave);

			return;
		}

		this->updateDataBSharp(data,clave);
	}


	void StorageResource::updateDataHash(Dato *data,Clave *clave){
		int fileReference;
		this->getIndexStategy()->updateIndex(fileReference,clave,data);
	}

	void StorageResource::updateDataBSharp(Dato *data,Clave *clave){
		
		int fileReference = this->getIndexStategy()->getStorageReferenceByKey(clave);

		if (fileReference != -1){

			int newPos=this->getStorageStrategy()->updateData(data,fileReference);

			if (fileReference!=newPos) {
			   this->getIndexStategy()->deleteKey(clave);
			   this->getIndexStategy()->updateIndex(newPos,clave,data);
			}
		}
	}

	Dato* StorageResource::getData(Clave *clave){


		int fileReference = this->getIndexStategy()->getStorageReferenceByKey(clave);

		if (fileReference == -1) return NULL; // No existe la clave buscada

		
		string datoSerializado = this->getStorageStrategy()->getData(clave,fileReference);

		this->getDato()->desSerializar(datoSerializado);

		return this->getDato();

	}

/*-----------------------------------------------------------------------------------------------------------*/

/*-------------------------Getter & Setters------------------------------------------------------------------*/
void StorageResource::setIndexStategy(IndexStrategy *indexStategy){
    this->indexStategy = indexStategy;
 }

IndexStrategy * StorageResource::getIndexStategy() const{
	return indexStategy;
}

ResourceStrategy * StorageResource::getResourceStrategy() const{
	return resourceStrategy;
}

StorageStrategy * StorageResource::getStorageStrategy() const{
	return storageStrategy;
}

Clave* StorageResource::getClave() const{
    return this->clave;
}

Dato* StorageResource::getDato() const{
    return this->data;
}

bool StorageResource::getCompressMode() const{
    return this->compressMode;
}

void StorageResource::setResourceStrategy(ResourceStrategy *resourceStrategy){
	this->resourceStrategy = resourceStrategy;
	if (this->compressMode==true) this->getResourceStrategy()->setCompressMode();
}

void StorageResource::setStorageStrategy(StorageStrategy *storageStrategy){
	this->storageStrategy = storageStrategy;
}

void StorageResource::setClave(Clave *clave){
	this->clave = clave;
}

void StorageResource::setCompressMode(bool comppressMode){
	this->compressMode = comppressMode;
	this->getResourceStrategy()->setCompressMode();

}

/*------------------------------------------------------------------------------------------------*/

void StorageResource::Saludar(){
	cout << "Soy un recurso" << endl;
}
